// 检测任务的标注结果
import labelDef from './Def';
import LabelConfig from '@/js/models/LabelConfig';
import { LabelBase } from '@/js/models/LabelBase';
import { getCurrentTime } from '@/js/utils/baseUtils';
import { setFObjectEditable, newRectFObject, newPolyFObject } from '@/js/utils/FabricControls';
import { calcPolyPoints, getPointsFromBBox, getPointsFromSegs, getPointsFromSeg, getPointsLT, getPointsRB, calculatePolygonBounds } from '@/js/utils/geomUtils';
import { getImageCoords, getCanvasCoords } from '@/js/utils/imageUtils';

export default class LabelDetection extends LabelBase {
    constructor(label_format) {
        super(label_format);

        // 工具回调函数
        this.tools_callback = {
            rect: this.rectToolCallback.bind(this),
            poly: this.polyToolCallback.bind(this)
        };

        // 存储geom数据
        this.labels_geom_rect = [];
        this.labels_geom_poly = [];
        this.last_selected_geoms = [];
        this.editing_label_id = -1;

        // 在组件中增加遮罩层相关变量
        this.highlight = false;
        this.mask_layer = null;
        this.MASK_COLOR = 'rgba(0, 0, 0, 0.7)';
    }

    ///====================以下定义geom显示相关的处理函数========================
    // 在canvas中渲染结果
    bindCanvas(canvas, image, label_tools) {
        // console.log('bindCanvas canvas = ', canvas);
        super.bindCanvas(canvas, image, label_tools);

        // 清除所有非图像对象
        const objects = canvas.getObjects();
        objects.forEach(obj => {
            if (obj !== image) {
                canvas.remove(obj);
            }
        });
        canvas.discardActiveObject();
        canvas.requestRenderAll();

        // 加载labels中的bbox和segmentation的数据
        for (let i = 0; i < this.labels.length; i++) {
            let label = this.labels[i];
            if (!label) continue;
            let bbox = this.paintBBox(label);
            let segs = this.paintSegmentation(label);
            this.labels_geom_rect[label.id] = bbox;
            this.labels_geom_poly[label.id] = segs;
            for (let j = 0; j < segs.length; j++) {
                this.canvas.add(segs[j]);
            }
        }

        for (let i = 0; i < this.labels_geom_rect.length; i++) {
            let rect = this.labels_geom_rect[i];
            rect && this.canvas.add(rect);
        }

        // 初始化遮罩层
        this.initMask();

        // 刷新显示
        this.canvas.requestRenderAll();
        return true;
    }

    setConfig(config) {
        // console.log(`setConfig config = `, config);
        for (let i = 0; i < this.labels_geom_rect.length; i++) {
            let geom = this.labels_geom_rect[i];
            if (geom) {
                geom.set({
                    visible: config.displayBbox
                });
            }
        }
        // console.log('this.labels_geom_poly = ', this.labels_geom_poly);
        for (let i = 0; i < this.labels_geom_poly.length; i++) {
            let geoms = this.labels_geom_poly[i];
            for (let j = 0; j < geoms.length; j++) {
                let geom = geoms[j];
                if (geom) {
                    geom.set({
                        visible: config.displaySeg
                    });
                }
            }
        }
        this.canvas.requestRenderAll();
    }

    paintBBox(label) {
        // console.log('paintBBox label = ', label);
        if (label.data.bbox.length == 0 || !this.image) {
            return;
        }

        let points = getPointsFromBBox(label.data.bbox);
        points = getCanvasCoords(this.image, points);
        let pt_tl = getPointsLT(points);
        let pt_rb = getPointsRB(points);
        let rect = newRectFObject(label.id, { left: pt_tl.x, top: pt_tl.y, width: pt_rb.x - pt_tl.x, height: pt_rb.y - pt_tl.y });
        // let text = new fabric.Text(label.data.category, {
        //     left: 0,
        //     top: -11,
        //     fontSize: 10,
        //     fontFamily: 'Arial',
        //     fill: '#ffffff',
        //     backgroundColor: 'rgba(0,200,0,1)'
        // });

        // let group = new fabric.Group([rect, text], {
        //     left: pt_tl.x,
        //     top: pt_tl.y - 10,
        //     label_id: label.id
        // });
        this.registerObjectEvents(rect);
        return rect;
    }

    paintSegmentation(label) {
        // console.warn('paintSegmentation segs = ', label.data.segmentation);
        let points = getPointsFromSegs(label.data.segmentation);
        if (points.length == 0) {
            return [];
        }

        let geom_polys = [];
        for (let i = 0; i < label.data.segmentation.length; i++) {
            let seg = label.data.segmentation[i];
            points = getPointsFromSeg(seg);
            points = getCanvasCoords(this.image, points);
            if (points && points.length > 0) {
                let pt_tl = getPointsLT(points);
                let poly = newPolyFObject(label.id, i, { points: points, left: pt_tl.x, top: pt_tl.y }, LabelConfig.getConfig('displaySeg'));
                geom_polys.push(poly);
                this.registerObjectEvents(poly);
            }
        }
        return geom_polys;
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 定义遮罩相关的处理函数
    onLabelMouseover(event) {
        // console.log(`[detection]onLabelMouseover event = `, event);
        if (this.highlight && event.target && event.target.type === 'rect') {
            event.target.hoverCursor = 'pointer';
            this.updateMask(event.target);
            this.canvas.requestRenderAll();
        }
    }

    onLabelMouseout(event) {
        // console.log(`[detection]onLabelMouseout event = `, event);
        if (this.highlight && event.target && event.target.type === 'rect') {
            this.updateMask(null);
            this.canvas.requestRenderAll();
        }
    }

    // 设置是否highlight选中对象
    setHighlight() {
        this.highlight = true;
    }

    // 初始化遮罩层
    initMask() {
        if (!this.canvas || !this.image) {
            return;
        }

        this.maskLayer = new fabric.Rect({
            originX: 'center',
            originY: 'center',
            left: this.canvas.width / 2,
            top: this.canvas.height / 2,
            width: this.image.width,
            height: this.image.height,
            fill: this.MASK_COLOR,
            selectable: false,
            evented: false,
            excludeFromExport: true,
            visible: false
        });
        this.canvas.add(this.maskLayer);
    }

    // 更新遮罩层
    updateMask(target) {
        if (!target || !this.canvas || !this.image) {
            this.maskLayer && this.maskLayer.set({ visible: false });
            return;
        }
        // 计算目标对象的包围盒
        const bound = {
            left: target.left,
            top: target.top,
            width: target.width,
            height: target.height
        };
        const clipPath = new fabric.Group(
            [
                // 全屏遮罩
                new fabric.Rect({
                    originX: 'center',
                    originY: 'center',
                    left: this.canvas.width / 2,
                    top: this.canvas.height / 2,
                    width: this.image.width,
                    height: this.image.height,
                    fill: this.MASK_COLOR
                }),
                // 挖空区域（反向蒙版）
                new fabric.Rect({
                    left: bound.left,
                    top: bound.top,
                    width: bound.width,
                    height: bound.height,
                    fill: 'white',
                    globalCompositeOperation: 'destination-out'
                })
            ],
            {
                absolutePositioned: true,
                selectable: false,
                evented: false
            }
        );

        // 更新遮罩层
        this.maskLayer.set({
            visible: true,
            clipPath: clipPath
        });
        this.maskLayer.bringToFront();
    }

    //////////////////////////////////////////////////////////////////////////////////////
    // 工具回调函数，更新外部UI显示
    rectToolCallback(rect) {
        // console.log('LabelDetection::rectToolCallback rect = ', rect, ' this = ', this);
        let label_id = Object.keys(this.labels_geom_rect).length;
        this.label_panel &&
            this.label_panel.showEditDialog('rect', label_id, (form) => {
                this.newRectLabel(rect, form);
            });
    }

    // 新增label（bbox）
    newRectLabel(rect, form) {
        // 在canvas中增加新增矩形框
        let label_id = Object.keys(this.labels_geom_rect).length;

        let rect_new = newRectFObject(label_id, rect);
        rect_new.set({ selectable: false, evented: false });

        this.canvas.add(rect_new);
        this.labels_geom_rect[label_id] = rect_new;
        this.registerObjectEvents(rect_new);
        this.labels_geom_poly[label_id] = null;

        // 在数据中增加新增矩形框
        let pts = [rect_new.aCoords.tl, rect_new.aCoords.tr, rect_new.aCoords.br, rect_new.aCoords.bl];
        let pts_bbox = getImageCoords(this.image, pts);
        let bbox = [pts_bbox[0].x, pts_bbox[0].y, pts_bbox[2].x, pts_bbox[2].y];

        let data = {};
        Object.assign(data, form);
        data.id = label_id;
        data.label_format = this.label_format;
        data.bbox = bbox;
        this.addLabel(data);

        // 在label_panel中增加新增矩形框
        this.label_panel && this.label_panel.addLabel(data);
    }

    polyToolCallback(poly) {
        // console.log('LabelDetection::polyToolCallback poly = ', poly);
        // 打开属性编辑框，设置属性值
        let label_id = Object.keys(this.labels_geom_poly).length;
        if (this.editing_label_id >= 0) {
            label_id = this.editing_label_id;
            console.log('polyToolCallback from existed label, label_id = ', label_id);
            this.addPolyToLabel(label_id, poly);
            this.editing_label_id = -1;
        } else {
            this.label_panel &&
                this.label_panel.showEditDialog('segmentation', label_id, (form) => {
                    this.newPolyLabel(poly, form);
                });
        }
    }

    //////////////////////////////////////////////////////////////////////////////////////
    // 新增label（segmentation）
    newPolyLabel(poly, form) {
        // console.log(form);
        // 创建新的polygon对象
        let label_id = Object.keys(this.labels_geom_poly).length;
        let poly_new = newPolyFObject(label_id, 0, poly);
        poly_new.set({ selectable: false, evented: false });
        // console.log(poly_new);

        // 添加polygon到canvas上
        this.canvas.add(poly_new);
        this.labels_geom_poly[label_id] = [poly_new];
        this.registerObjectEvents(poly_new);
        this.labels_geom_rect[label_id] = null;

        // 在数据中增加新增多边形
        let points = getImageCoords(this.image, poly.points);
        let seg = points.flatMap(({ x, y }) => [x, y]);
        let data = {};
        Object.assign(data, form);
        data.id = label_id;
        data.label_format = this.label_format;
        data.segmentation = [seg];

        // 判断是否自动创建bbox
        if (form.autobbox) {
            // 创建新的rect对象
            let { left, top, right, bottom } = calculatePolygonBounds(poly.points);
            let pts = [
                { x: left, y: top },
                { x: right, y: bottom }
            ];
            let rect_new = newRectFObject(label_id, { left: left, top: top, width: right - left, height: bottom - top });
            rect_new.set({ selectable: false, evented: false });

            // 添加bbox到canvas上
            this.canvas.add(rect_new);
            this.labels_geom_rect[label_id] = rect_new;
            this.registerObjectEvents(rect_new);

            // 在数据中增加bbox
            let pts_bbox = getImageCoords(this.image, pts);
            let bbox = [pts_bbox[0].x, pts_bbox[0].y, pts_bbox[1].x, pts_bbox[1].y];
            data.bbox = bbox;
        }
        this.addLabel(data);

        // 在label_panel中增加新增矩形框
        this.label_panel && this.label_panel.addLabel(data);
    }

    // 在已有label中，增加一个新的poly对象
    addPolyToLabel(label_id, poly) {
        // 创建新的polygon对象
        let label = this.labels[label_id];
        let seg_index = label.data.segmentation.length;
        let poly_new = newPolyFObject(label_id, seg_index, poly);
        poly_new.set({ selectable: false, evented: false });
        // console.log(poly_new);

        // 添加polygon到canvas上
        this.canvas.add(poly_new);
        this.registerObjectEvents(poly_new);
        let geom_poly = this.labels_geom_poly[label_id];
        if (geom_poly) {
            geom_poly.push(poly_new);
        } else {
            geom_poly = [poly_new];
        }

        // 在数据中增加新增多边形
        let points = getImageCoords(this.image, poly.points);
        let seg = points.flatMap(({ x, y }) => [x, y]);
        let segs = label.data.segmentation;
        segs && segs.push(seg);
        let update_info = {
            id: label_id,
            segmentation: segs
        };
        this.updateLabel(update_info);
    }

    // 删除标注里面的某一个seg
    deletePolyFromLabel(label_id, seg_index) {
        console.log(`deletePolyFromLabel label_id = ${label_id}, seg_index = ${seg_index}`);
        let label = this.labels[label_id];
        if (label) {
            if (seg_index >= 0 && seg_index < label.data.segmentation.length) {
                let geoms_poly = this.labels_geom_poly[label_id];
                let geom = this.labels_geom_poly[label_id][seg_index];

                // 将poly从成员变量中删除
                this.last_selected_geoms = this.last_selected_geoms.filter((item) => item !== geom);
                geoms_poly.splice(seg_index, 1);

                // 将poly从canvas中删除
                this.canvas.remove(geom);

                // 将poly从数据中删除
                label.data.segmentation.splice(seg_index, 1);

                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    // 设置对象是否可以编辑
    setEditableMode(editable = true) {
        // console.log('setEditableMode editable = ', editable);
        let evented = (!this.highlight && !editable) ? false : true;
        this.unselectLabel();
        for (let i = 0; i < this.labels_geom_rect.length; i++) {
            let geom = this.labels_geom_rect[i];
            if (geom) {
                geom.set({
                    selectable: editable,
                    evented: evented
                });
            }
        }

        for (let i = 0; i < this.labels_geom_poly.length; i++) {
            let geoms = this.labels_geom_poly[i];
            if (geoms) {
                for (let j = 0; j < geoms.length; j++) {
                    let geom = geoms[j];
                    if (geom) {
                        geom.set({
                            selectable: editable,
                            evented: editable
                        });
                    }
                }
            }
        }
        this.canvas.requestRenderAll();
    }

    onLabelModified(event) {
        // console.log('LabelDetection::onLabelModified event = ', event);
        // 读取fabricjs更新后的信息
        let label_id = event.target.label_id;
        let geom = event.target;
        let points = null;
        let update_info = {
            id: label_id
        };
        if (geom && geom.data.type == 'bbox') {
            points = [geom.aCoords.tl, geom.aCoords.tr, geom.aCoords.br, geom.aCoords.bl];
            points = getImageCoords(this.image, points);
            update_info['bbox'] = [points[0].x, points[0].y, points[2].x, points[2].y];
        } else if (geom && geom.data.type == 'segm') {
            // console.log('geom = ', geom);
            points = calcPolyPoints(geom.points, { x: geom.left, y: geom.top });
            points = getImageCoords(this.image, points);
            let seg_index = geom.seg_index;
            let seg = points.flatMap(({ x, y }) => [x, y]);
            update_info['segmentation'] = [];
            update_info['segmentation'][seg_index] = seg;
        } else {
        }

        // console.log('update_info = ', update_info);
        // 更新数据中存储的信息
        this.updateLabel(update_info);

        // 在label_panel中更新信息
        this.label_panel && this.label_panel.updateStatus();
    }

    selectLabel(label_id, target = null) {
        // console.log(`selectLabel label_id = ${label_id}, target = `, target);
        // 在canvas中选择标签对象
        if (!(label_id in this.labels_geom_rect)) {
            return;
        }

        // 取消选择，并根据是否有点击的具体对象，将需要选中的对象都放到selected_geoms中
        this.unselectLabel();

        // 放置待选择的对象
        let select_geoms = [];
        if (target) {
            select_geoms = [target];
        } else {
            select_geoms = [];
            let rect = this.labels_geom_rect[label_id];
            if (rect) {
                select_geoms.push(rect);
            }
            let polys = this.labels_geom_poly[label_id];
            if (polys) {
                for (let i = 0; i < polys.length; i++) {
                    let poly = polys[i];
                    select_geoms.push(poly);
                }
            }
        }

        // 设置fabricjs的geom对象，选中的属性
        for (let i = 0; i < select_geoms.length; i++) {
            let geom = select_geoms[i];
            if (geom) {
                geom.set({
                    fill: 'rgba(200,0,0,0.2)',
                    stroke: 'rgba(200,0,0,1.0)'
                });
                setFObjectEditable(geom);
            }
        }

        // 设置activateobject
        if (target) {
            this.canvas.setActiveObject(target);
        } else {
            this.canvas.setActiveObject(select_geoms[0]);
        }
        this.last_selected_geoms = select_geoms;
        this.canvas.requestRenderAll();

        // 在label_panel中选择标签对象
        this.label_panel && this.label_panel.selectLabel(label_id);
    }

    unselectLabel() {
        // 在canvas中取消选择label
        // console.log(`## this.last_selected_geoms = `, this.last_selected_geoms);
        for (let i = 0; i < this.last_selected_geoms.length; i++) {
            let geom = this.last_selected_geoms[i];
            if (geom && geom.data && geom.data.type === 'bbox' || geom.data.type === 'segm') {
                let type = geom.type;
                let config = {
                    fill: LabelConfig.getConfig(`${type}_style.fill`),
                    strokeWidth: LabelConfig.getConfig(`${type}_style.strokeWidth`),
                    stroke: LabelConfig.getConfig(`${type}_style.stroke`),
                    hasControls: false
                };
                geom.set(config);
            }
        }
        this.last_selected_geoms = [];

        // 在label_panel中取消选择panel
        this.label_panel && this.label_panel.selectLabel(-1);
    }

    // 删除当前选中的label
    deleteSelection() {
        // console.log('deleteSelection last_selected_geoms = ', this.last_selected_geoms);
        if (this.last_selected_geoms.length > 0) {
            let label_id = this.last_selected_geoms[0].label_id;
            this.deleteLabel(label_id);
            this.last_selected_geoms = [];
        }
    }

    ///========================以下定义数据相关的处理函数========================
    // 新增标注结果
    addLabel(data) {
        // console.log('LabelDetection addLabel data = ', data);
        this.labels[data.id] = this.labelOfBase(data.id, 'vision:detection', labelDef(data));
        // console.log('this.labels[data.id] = ', this.labels[data.id]);
        this.saved = false;
        return true;
    }

    // 更新对应的labelid信息，可以更新poly或者text文本
    updateLabel(data) {
        // console.log(`LabelDetection::updateLabel data = `, data);
        let label_id = data.id;
        if (label_id in this.labels) {
            let label = this.labels[label_id];
            if (label) {
                for (let key in data) {
                    if (key === 'id') continue;
                    label.data[key] = data[key];
                }
                label.score = 1.0;
                label.timestamp = getCurrentTime();
                this.saved = false;
            }
            return true;
        } else {
            return false;
        }
    }

    deleteLabel(label_id) {
        // console.log('LabelDetection::deleteLabel label_id = ', label_id);
        // 从canvas中删除
        if (this.canvas && label_id in this.labels_geom_rect) {
            let rect = this.labels_geom_rect[label_id];
            rect && this.canvas.remove(rect);
            this.labels_geom_rect[label_id] = null;

            let polys = this.labels_geom_poly[label_id];
            if (polys) {
                for (let i = 0; i < polys.length; i++) {
                    polys[i] && this.canvas.remove(polys[i]);
                }
            }
            this.labels_geom_poly[label_id] = null;
        }

        // 从label_panel中删除
        this.label_panel && this.label_panel.deleteLabel(label_id, false);

        // 从数据中删除
        if (label_id in this.labels) {
            this.labels[label_id] = null;
            this.saved = false;
            return true;
        } else {
            return false;
        }
    }

    clearLabels() {
        this.labels = [];
        this.saved = false;
        return true;
    }

    fromJson(json_data) {
        this.labels = [];
        for (let i = 0; i < json_data.length; i++) {
            let data = json_data[i];
            this.labels[data.id] = this.labelOfBase(data.id, 'vision:detection', data);
        }
    }

    toJson() {
        let results = [];
        for (let i = 0; i < this.labels.length; i++) {
            let label = this.labels[i];
            if (label) {
                label.id = results.length;
                results.push(label);
            }
        }
        let json_str = JSON.stringify(results);
        return json_str;
    }
}
